/**
 * 解决事件处理函数this指向问题的四种方式中哪些推荐哪些不推荐
 *  1. 【推荐】 在构造函数中统一处理 this 指向的绑定
 *  2. 【最推荐】创建事件处理函数时，使用 Public class fields + 箭头函数 语法
 *  3. 传递事件处理函数时，使用 箭头函数
 *     箭头函数才是事件处理函数，原本的函数变成了一个普通函数在调用
 *  4. 传递事件处理函数时，使用 bind 绑定 this
 *
 *
 *  当将一个处理了this指向的函数传递给子组件时，且该子组件做了PureComponent的时候，推荐使用第一种与第二种方案来处理this指向问题
 *
 *  原因是：第三种与第四种，在父组件Render的时候，传递给子组件的函数时一个新生成的函数，不是同一个引用，导致子组件内部 PureComponent
 *      做 prop 的比较时，认为 prop 有变化，就会 ReRender。最终导致子组件 PureComponent 没有起到作用。
 */

import React from "react";

interface AppProps {}
interface AppState {
  count: number;
  sonName: string;
  sonAge: number;
}

interface HelloProps {
  name: string;
  age: number;
  onChange: () => void;
}

class Hello extends React.PureComponent<HelloProps> {
  render() {
    console.log("Hello Render", this.props);
    return (
      <div>
        <h4>Hello</h4>
        <p>Name: {this.props.name}</p>
        <p>Age: {this.props.age}</p>
        <button
          onClick={() => {
            this.props.onChange();
          }}
        >
          点我，调用传递过来的onChange
        </button>
      </div>
    );
  }
}

class App extends React.Component<AppProps, AppState> {
  state: Readonly<AppState> = {
    count: 1,

    sonName: "张三",
    sonAge: 18,
  };

  constructor(props: AppProps) {
    super(props);

    this.handleChange = this.handleChange.bind(this);
  }

  handleClick = () => {
    this.setState((state) => ({ count: state.count + 1 }));
  };

  handleChangeName = () => {
    this.setState((state) => ({
      sonName: state.sonName === "张三~~~" ? "张三~~~" : state.sonName + "~",
    }));
  };

  handleChangeAge = () => {
    this.setState((state) => ({ sonAge: state.sonAge + 1 }));
  };

  handleChange() {
    console.log("handleChange", this);
    this.setState((state) => ({ sonAge: state.sonAge + 1 }));
  }

  render() {
    console.log("App Render");
    return (
      <div>
        <h1>App</h1>
        <button onClick={this.handleClick}>点我, {this.state.count}</button>
        <button onClick={this.handleChangeName}>{this.state.sonName}</button>
        <button onClick={this.handleChangeAge}>{this.state.sonAge}</button>

        <hr />
        <Hello
          name={this.state.sonName}
          age={this.state.sonAge}
          onChange={() => this.handleChange()}
        />
      </div>
    );
  }
}

export default App;
